﻿using SDL2;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace audiotest
{
    public class SDLWindow
    {
        private SDLWindow()
        {

        }
        public static SDLWindow Create(IntPtr windowPtr)
        {
            SDLWindow win = new SDLWindow();
            win.windowPtr = windowPtr;
            var tagetsurface = SDL.SDL_GetWindowSurface(win.windowPtr);
            SDL.SDL_Surface tt = Marshal.PtrToStructure<SDL.SDL_Surface>(tagetsurface);
            var ttformat = Marshal.PtrToStructure<SDL.SDL_PixelFormat>(tt.format);
            win.surfaceFix = SDL.SDL_CreateRGBSurfaceWithFormat(0, 256, 240, ttformat.BitsPerPixel, ttformat.format);
            win.id = SDL.SDL_GetWindowID(win.windowPtr);

            return win;
        }
        public uint id
        {
            get;
            private set;
        }
        public IntPtr windowPtr
        {
            get;
            private set;
        }
        public IntPtr surfaceFix
        {
            get;
            private set;
        }
        public SDLSurface surfaceNES
        {
            get;
            set;
        }
        public void UpdateWindow()
        {

            SDL.SDL_Rect src = new SDL.SDL_Rect() { x = 0, y = 0, w = 256, h = 240 };
            if (surfaceNES != null)
                SDL.SDL_BlitSurface(surfaceNES.surfacePtr, ref src, surfaceFix, ref src);

            var tagetsurface = SDL.SDL_GetWindowSurface(windowPtr);
            SDL.SDL_GetWindowSize(windowPtr, out int ww, out int wh);
            SDL.SDL_Rect windest = new SDL.SDL_Rect() { x = 0, y = 0, w = ww, h = wh };
            SDL.SDL_SoftStretch(surfaceFix, ref src, tagetsurface, ref windest);
            SDL.SDL_UpdateWindowSurface(windowPtr);

        }

        public void OnUpdate()
        {
            UpdateWindow();
        }
        public void OnEvent(SDL.SDL_WindowEvent _event)
        {
            if (_event.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED)
            {
                UpdateWindow();
            }
        }
        public event Action<SDL.SDL_Keysym, bool> eventOnKey;
        public void OnKey(SDL.SDL_Keysym key, bool press)
        {
            eventOnKey?.Invoke(key, press);
        }

    }
    public class SDLSurface
    {
        private SDLSurface()
        {

        }
        public static SDLSurface Create(IntPtr surfacePtr)
        {
            SDLSurface sur = new SDLSurface();
            sur.surfacePtr = surfacePtr;
            sur.surfaceStruct = Marshal.PtrToStructure<SDL.SDL_Surface>(sur.surfacePtr);

            //var palette = SDL.SDL_AllocPalette(256);
            //SDL.SDL_Color[] colors = new SDL.SDL_Color[256];
            //System.Func<byte, byte, byte, SDL.SDL_Color> FromRgb = (r, g, b) => new SDL.SDL_Color() { r = r, g = g, b = b, a = 255 };
            //colors[0x0] = FromRgb(84, 84, 84);
            //colors[0x1] = FromRgb(0, 30, 116);
            //colors[0x2] = FromRgb(8, 16, 144);
            //colors[0x3] = FromRgb(48, 0, 136);
            //colors[0x4] = FromRgb(68, 0, 100);
            //colors[0x5] = FromRgb(92, 0, 48);
            //colors[0x6] = FromRgb(84, 4, 0);
            //colors[0x7] = FromRgb(60, 24, 0);
            //colors[0x8] = FromRgb(32, 42, 0);
            //colors[0x9] = FromRgb(8, 58, 0);
            //colors[0xa] = FromRgb(0, 64, 0);
            //colors[0xb] = FromRgb(0, 60, 0);
            //colors[0xc] = FromRgb(0, 50, 60);
            //colors[0xd] = FromRgb(0, 0, 0);
            //colors[0xe] = FromRgb(0, 0, 0);
            //colors[0xf] = FromRgb(0, 0, 0);
            //colors[0x10] = FromRgb(152, 150, 152);
            //colors[0x11] = FromRgb(8, 76, 196);
            //colors[0x12] = FromRgb(48, 50, 236);
            //colors[0x13] = FromRgb(92, 30, 228);
            //colors[0x14] = FromRgb(136, 20, 176);
            //colors[0x15] = FromRgb(160, 20, 100);
            //colors[0x16] = FromRgb(152, 34, 32);
            //colors[0x17] = FromRgb(120, 60, 0);
            //colors[0x18] = FromRgb(84, 90, 0);
            //colors[0x19] = FromRgb(40, 114, 0);
            //colors[0x1a] = FromRgb(8, 124, 0);
            //colors[0x1b] = FromRgb(0, 118, 40);
            //colors[0x1c] = FromRgb(0, 102, 120);
            //colors[0x1d] = FromRgb(0, 0, 0);
            //colors[0x1e] = FromRgb(0, 0, 0);
            //colors[0x1f] = FromRgb(0, 0, 0);
            //colors[0x20] = FromRgb(236, 238, 236);
            //colors[0x21] = FromRgb(76, 154, 236);
            //colors[0x22] = FromRgb(120, 124, 236);
            //colors[0x23] = FromRgb(176, 98, 236);
            //colors[0x24] = FromRgb(228, 84, 236);
            //colors[0x25] = FromRgb(236, 88, 180);
            //colors[0x26] = FromRgb(236, 106, 100);
            //colors[0x27] = FromRgb(212, 136, 32);
            //colors[0x28] = FromRgb(160, 170, 0);
            //colors[0x29] = FromRgb(116, 196, 0);
            //colors[0x2a] = FromRgb(76, 208, 32);
            //colors[0x2b] = FromRgb(56, 204, 108);
            //colors[0x2c] = FromRgb(56, 180, 204);
            //colors[0x2d] = FromRgb(60, 60, 60);
            //colors[0x2e] = FromRgb(0, 0, 0);
            //colors[0x2f] = FromRgb(0, 0, 0);
            //colors[0x30] = FromRgb(236, 238, 236);
            //colors[0x31] = FromRgb(168, 204, 236);
            //colors[0x32] = FromRgb(188, 188, 236);
            //colors[0x33] = FromRgb(212, 178, 236);
            //colors[0x34] = FromRgb(236, 174, 236);
            //colors[0x35] = FromRgb(236, 174, 212);
            //colors[0x36] = FromRgb(236, 180, 176);
            //colors[0x37] = FromRgb(228, 196, 144);
            //colors[0x38] = FromRgb(204, 210, 120);
            //colors[0x39] = FromRgb(180, 222, 120);
            //colors[0x3a] = FromRgb(168, 226, 144);
            //colors[0x3b] = FromRgb(152, 226, 180);
            //colors[0x3c] = FromRgb(160, 214, 228);
            //colors[0x3d] = FromRgb(160, 162, 160);
            //colors[0x3e] = FromRgb(0, 0, 0);
            //colors[0x3f] = FromRgb(0, 0, 0);
            //for (var i = 0x40; i < 256; i++)
            //{
            //    colors[i] = FromRgb(0, 0, 0);
            //}
            //var nn1 = SDL.SDL_SetPaletteColors(palette, colors, 0, 256);
            //var nn2 = SDL.SDL_SetSurfacePalette(sur.surfacePtr, palette);

            return sur;
        }
        public IntPtr surfacePtr
        {
            get;
            private set;
        }
        private SDL.SDL_Surface surfaceStruct;

        public IntPtr Lock(out int pitch)
        {
            SDL.SDL_LockSurface(surfacePtr);

            pitch = surfaceStruct.pitch;
            return surfaceStruct.pixels;
        }
        public void UnLock()
        {
            SDL.SDL_UnlockSurface(surfacePtr);
        }
        public unsafe void SetPixels(int[] data, int datapitch, int dataline)
        {
            int srcwidth = Math.Min(256, datapitch);
            var pixels = this.Lock(out int pitch);
            {
                for (var y = 0; y < dataline; y++)
                {
                    int* linestart = (int*)(pixels + pitch * y);
                    for (var x = 0; x < srcwidth; x++)
                    {
                        var c = data[y * datapitch + x];
                        linestart[x] = c;
                    }
                }
            }
            this.UnLock();
        }
    }

    public class SDLTool
    {
        public static SDLWindow CreateNESWindow(string title, int width, int height)
        {
            var windowPtr = SDL.SDL_CreateWindow(title, SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED, width, height, SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN | SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE);

            SDLWindow win = SDLWindow.Create(windowPtr);

            windows[win.id] = win;
            return win;
        }
        public static SDLSurface CreateNesTargetSurface()
        {
            var bmp1 = SDL.SDL_CreateRGBSurfaceWithFormat(0, 256, 240, 32, SDL.SDL_PIXELFORMAT_ARGB8888);
            return SDLSurface.Create(bmp1);
        }

        static Dictionary<uint, SDLWindow> windows = new Dictionary<uint, SDLWindow>();
        public static void SDLMainLoop()
        {
            while (!bExit)
            {
                int dd = SDL.SDL_PollEvent(out SDL.SDL_Event _event);
                if (dd > 0)
                {
                    if (_event.type == SDL.SDL_EventType.SDL_WINDOWEVENT)
                    {
                        windows[_event.window.windowID].OnEvent(_event.window);
                        if (_event.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE)
                        {
                            bExit = true;
                            continue;
                        }
                    }
                    if (_event.type == SDL.SDL_EventType.SDL_KEYDOWN)
                    {
                        windows[_event.window.windowID].OnKey(_event.key.keysym, true);
                    }
                    if (_event.type == SDL.SDL_EventType.SDL_KEYUP)
                    {
                        windows[_event.window.windowID].OnKey(_event.key.keysym, false);
                    }
                }
                foreach (var w in windows)
                {
                    w.Value.OnUpdate();
                }
                OnFrameUpdate?.Invoke();
                System.Threading.Thread.Sleep(1);
            }
        }
        static bool bExit = false;
        public static void Exit()
        {
            bExit = true;
        }
        public static event Action OnFrameUpdate;
    }
}
